package sg.edu.nus.iss.billing.dummyData;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

import sg.edu.nus.iss.billing.common.DbUtil;
import sg.edu.nus.iss.billing.common.Util;
import sg.edu.nus.iss.billing.common.exception.BadDaoCallException;
import sg.edu.nus.iss.billing.common.exception.BadDbCallException;
import sg.edu.nus.iss.billing.common.exception.InvalidParamsException;
import sg.edu.nus.iss.billing.dao.account.AccountDAO;
import sg.edu.nus.iss.billing.dao.bill.TransactionDAO;
import sg.edu.nus.iss.billing.dao.customer.CustomerDAO;
import sg.edu.nus.iss.billing.dao.subscription.SubscriptionDAO;
import sg.edu.nus.iss.billing.vo.account.AccountVO;
import sg.edu.nus.iss.billing.vo.customer.AddressVO;
import sg.edu.nus.iss.billing.vo.customer.CustomerVO;
import sg.edu.nus.iss.billing.vo.subscription.CableTvVO;
import sg.edu.nus.iss.billing.vo.subscription.DigitalVoiceVO;
import sg.edu.nus.iss.billing.vo.subscription.MobileVoiceVO;
import sg.edu.nus.iss.billing.vo.subscription.SubscriptionVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.CallTransferFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.ChannelFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.DataServiceFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.FeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.IDDCallFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.LocalCallFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.PremiumChannelFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.RoamingCallFeatureVO;
import sg.edu.nus.iss.billing.vo.subscription.feature.StandardChannelFeatureVO;
import sg.edu.nus.iss.billing.vo.transaction.TransactionVO;

public class DataGenerator {

	SubscriptionDAO subDao = new SubscriptionDAO();
	TransactionDAO transDao = new TransactionDAO();
	AccountDAO accDao = new AccountDAO();
	CustomerDAO cusDao = new CustomerDAO();
	ArrayList<String> surnames = new ArrayList<String> ();
	ArrayList<String> midNames = new ArrayList<String> ();
	ArrayList<String> lastNames = new ArrayList<String> ();
	
	public DataGenerator() {
		surnames.add("Tan");
		surnames.add("Pan");
		surnames.add("Anderson");
		surnames.add("Ahmed");
		surnames.add("Mukherjee");
		midNames.add("Chee");
		midNames.add("Jian");
		midNames.add("Jon");
		midNames.add("Tinesh");
		midNames.add("Ali");
		lastNames.add("Ann");
		lastNames.add("Gupta");
		lastNames.add("Eric");
		lastNames.add("Ling");
		lastNames.add("Shaiful");
	}
	
	private String generateRandomName() {
		StringBuilder sb = new StringBuilder();
		Random r = new Random();
		sb.append(surnames.get(r.nextInt(surnames.size())));
		sb.append(" ");
		sb.append(midNames.get(r.nextInt(midNames.size())));
		sb.append(" ");
		sb.append(lastNames.get(r.nextInt(lastNames.size())));
		return sb.toString();
	}
	
	private String generatePostalCode() {
		Random r = new Random();
		int no = r.nextInt(999999);
		return String.format("%06d", no);
	}
	
	public void createAccount() throws BadDaoCallException, Exception {
		ArrayList<SubscriptionVO> plans = (ArrayList<SubscriptionVO>) subDao.getAllSubscriptionPlan();
		AccountVO acct = new AccountVO();
		String accountNo = "ACCT-" + Util.generateRandomNumer();
		String nric = Util.generateRandomNric();
		
		acct.setAccountNo(accountNo);
		acct.setNric(nric);
		acct.setStatus(Util.ACCOUNT_STATUS_INACTIVE);
		accDao.createAccount(acct);
		
		CustomerVO customer = new CustomerVO();
		customer.setNric(nric);
		customer.setCustomerNme(generateRandomName());
		customer.getAccount().setAccountNo(accountNo);
		customer.setContactNo(Util.generateRandomPhoneNumber());
		customer.setInterest("I love to code");
		
		AddressVO addr = new AddressVO();
		addr.setAddresseeNric(nric);
		addr.setCity("Singapore");
		addr.setCountry("Singapore");
		addr.setState("Singapore");
		addr.setPostalCode(generatePostalCode());
		Random r = new Random();
		addr.setLine1("" + r.nextInt(999) + " Kent Ridge");
		addr.setLine2("#" + r.nextInt(999) + "-" + r.nextInt(999));
		customer.setAddress(addr);
		cusDao.create(customer);
		
		for (int i=0; i< plans.size(); i++) {
			if (r.nextInt(2) == 1) {
				if (plans.get(i).getClass().equals(CableTvVO.class)) {
					createCableTvSubscription((CableTvVO) plans.get(i), accountNo);
				} else if (plans.get(i).getClass().equals(DigitalVoiceVO.class)) {
					createDigitalVoiceSubscription((DigitalVoiceVO)plans.get(i), accountNo);
				} else if (plans.get(i).getClass().equals(MobileVoiceVO.class)) {
					createMobileVoiceSubscription((MobileVoiceVO)plans.get(i), accountNo);
				}
			}
		}

	}

	public void createCableTvSubscription(CableTvVO plan, String accountNo) {
		System.out.println("Creating Cable TV");
		Random r = new Random();
		CableTvVO cable = new CableTvVO();
		Date startDate = Util.getRandomDateAgo(5);
		String subscriptionId = "S-"+Util.generateRandomNumer();
		try {
			cable.setParameters(plan.serialised());
			cable.setAccNo(accountNo);
			cable.setSubsId(subscriptionId);
			cable.setStartDate(startDate);
			cable.clearChannels();
			cable.setStatus(Util.ACCOUNT_STATUS_ACTIVE);
			ArrayList<ChannelFeatureVO> options = plan.getAllAddonChannel();
			// select essential channels
			int cnt = 0;
			int added = 0;
			while (cnt<options.size()) {
				if (options.get(cnt).getClass().equals(StandardChannelFeatureVO.class)) {
					if (r.nextInt(2) == 1) {
						StandardChannelFeatureVO ch = new StandardChannelFeatureVO();
						ch.setParameters(options.get(cnt).serialised());
						ch.setStartDate(startDate);
						cable.addStandardChannel(ch);
						options.remove(cnt);
						added++;
						System.out.println("Adding Standard" + ch.getDescription());
					}
				}
				cnt++;
				if (cnt == options.size()) {
					cnt = 0;
				}
				if (added==3) {
					cnt = options.size();
				}
			}
			// randomly select 0..max channels
			for (int i=0; i< options.size(); i++) {
				try {
					ChannelFeatureVO ch = options.get(i).getClass().newInstance();
					ch.setParameters(options.get(i).serialised());
					ch.setStartDate(startDate);
					cable.addChannel(ch);
					System.out.println("Adding Addon" + ch.getDescription());
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		} catch (InvalidParamsException e) {
			// fail to get plans, abort creation.
			e.printStackTrace();
		}
		// createSubscription
		subDao.createSubscription(cable);
	}

	public void createMobileVoiceSubscription(MobileVoiceVO plan, String accountNo) throws BadDbCallException {
		System.out.println("Creating Mobile");
		Random r = new Random();
		MobileVoiceVO mobile = new MobileVoiceVO();
		Date startDate = Util.getRandomDateAgo(5);
		String subscriptionId = "S-"+Util.generateRandomNumer();
		try {
			mobile.setParameters(plan.serialised());
			mobile.clearFeatures();
			mobile.setAccNo(accountNo);
			mobile.setSubsId(subscriptionId);
			mobile.setStartDate(startDate);
			mobile.setStatus(Util.ACCOUNT_STATUS_ACTIVE);
			ArrayList<FeatureVO> options = plan.getAllOptionalFeature();
			// select essential channels
			int idx =0;
			for (int i=0; i<options.size(); i++) {
				if (options.get(i).getClass().equals(LocalCallFeatureVO.class)) {
					LocalCallFeatureVO localcall = new LocalCallFeatureVO();
					localcall.setParameters(options.get(i).serialised());
					localcall.setStartDate(startDate);
					mobile.setLocalCallFeatureVO(localcall);
					idx =i;
					System.out.println("Adding Local");
				}
			}
			options.remove(idx);

			// fill in transaction data
			int numSample = 50;
			for (int i=0; i<numSample; i++) {
				Calendar cal = Calendar.getInstance();
				cal.add(Calendar.DAY_OF_YEAR, r.nextInt(100)*-1);
				createTransaction(subscriptionId, Util.TRANSACTIONVO_LOCALCALL, 
						Util.generateRandomPhoneNumber(), cal.getTime(), r.nextInt(6000));
			}

			// randomly select 0..max channels
			for (int i=0; i< options.size(); i++) {
				if (r.nextInt(2) == 1) {
					try {
						FeatureVO feat = options.get(i).getClass().newInstance();
						feat.setParameters(options.get(i).serialised());
						feat.setStartDate(startDate);
						mobile.addOptionalFeatures(feat);
						System.out.println("Adding Feature" + feat.getDescription());
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
			
			for (int i = 0; i < mobile.getAllOptionalFeature().size(); i++) {
				for (int j = 0; j < numSample; j++) {
					Calendar cal = Calendar.getInstance();
					cal.add(Calendar.DAY_OF_YEAR, r.nextInt(100) * -1);
					FeatureVO feat = mobile.getAllOptionalFeature().get(i);
					createTransaction(subscriptionId,
							feat.getName(),
							Util.generateRandomPhoneNumber(), cal.getTime(),
							r.nextInt(6000));
				}
			}
		} catch (InvalidParamsException e) {
			// fail to get plans, abort creation.
			e.printStackTrace();
		}

		// create mobile voice
		subDao.createSubscription(mobile);
	}

	public void createDigitalVoiceSubscription(DigitalVoiceVO plan, String accountNo) throws BadDbCallException {
		System.out.println("Creating Digital");
		Random r = new Random();
		DigitalVoiceVO digital = new DigitalVoiceVO();
		Date startDate = Util.getRandomDateAgo(5);
		String subscriptionId = "S-"+Util.generateRandomNumer();
		try {
			digital.setParameters(plan.serialised());
			digital.clearFeatures();
			digital.setAccNo(accountNo);
			digital.setSubsId(subscriptionId);
			digital.setStartDate(startDate);
			digital.setStatus(Util.ACCOUNT_STATUS_ACTIVE);
			ArrayList<FeatureVO> options = plan.getAllOptionalFeature();
			
			LocalCallFeatureVO localcall = new LocalCallFeatureVO();
			localcall.setParameters(plan.getLocalCallFeatureVO().serialised());
			localcall.setStartDate(startDate);
			digital.setLocalCallFeatureVO(localcall);
			
			// fill in transaction data
			int numSample = 50;
			for (int i=0; i<numSample; i++) {
				Calendar cal = Calendar.getInstance();
				cal.add(Calendar.DAY_OF_YEAR, r.nextInt(100)*-1);
				createTransaction(subscriptionId, Util.TRANSACTIONVO_LOCALCALL, 
						Util.generateRandomPhoneNumber(), cal.getTime(), r.nextInt(6000));
			}

			System.out.println(options.size());
			// randomly select 0..max channels
			for (int i=0; i< options.size(); i++) {
				if (r.nextInt(2) == 1) {
					try {
						FeatureVO feat = options.get(i).getClass().newInstance();
						feat.setParameters(options.get(i).serialised());
						feat.setStartDate(startDate);
						digital.addOptionalFeatures(feat);
						System.out.println("Adding " + feat.getName());
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
			

			for (int i = 0; i < digital.getAllOptionalFeature().size(); i++) {
				for (int j = 0; j < numSample; j++) {
					
					Calendar cal = Calendar.getInstance();
					cal.add(Calendar.DAY_OF_YEAR, r.nextInt(100) * -1);
					FeatureVO feat = digital.getAllOptionalFeature().get(i);
					createTransaction(subscriptionId,
							feat.getName(),
							Util.generateRandomPhoneNumber(), cal.getTime(),
							r.nextInt(6000));
				}
			}
		} catch (InvalidParamsException e) {
			// fail to get plans, abort creation.
			e.printStackTrace();
		}

		// create digital voice
		subDao.createSubscription(digital);
	}

	public void createTransaction(String sId, String featureName, String numberCalled, Date transactionDate, double duration) throws BadDbCallException {
		try {
			Class<?> o = Util.getTransactionVOMap().get(featureName);
			if (o != null) {
				TransactionVO transaction = (TransactionVO) o.newInstance();
				transaction.setSubscriptionId(sId);
				transaction.setNumberCalled(numberCalled);
				transaction.setTransactionDate(transactionDate);
				transaction.setCallDuration(duration);
				// create
				try {
					transDao.createTransaction(transaction);
				} catch (BadDbCallException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}	
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public void createPlansData() {
		//Create plan
		try {
			ArrayList<String> serialisedPlans = (ArrayList<String>) DbUtil.loadDb( "data//plans.txt");
			if (serialisedPlans.size() != 3) {
				System.out.println ("Generating Plans");
				CableTvVO cable = new CableTvVO();
				cable.setDescription("One/# cable television service.");
				cable.setMonthlySuscription(25);

				StandardChannelFeatureVO ch1 = new StandardChannelFeatureVO();
				ch1.setChannelCode("01");
				ch1.setDescription("Local News");
				ch1.setSubscriptionRate(10);
				cable.addChannel(ch1);

				StandardChannelFeatureVO ch2 = new StandardChannelFeatureVO();
				ch2.setChannelCode("02");
				ch2.setDescription("English");
				ch2.setSubscriptionRate(10);
				cable.addChannel(ch2);

				StandardChannelFeatureVO ch3 = new StandardChannelFeatureVO();
				ch3.setChannelCode("03");
				ch3.setDescription("World News");
				ch3.setSubscriptionRate(10);
				cable.addChannel(ch3);

				StandardChannelFeatureVO ch4 = new StandardChannelFeatureVO();
				ch4.setChannelCode("04");
				ch4.setDescription("Lifestyle");
				ch4.setSubscriptionRate(10);
				cable.addChannel(ch4);

				StandardChannelFeatureVO ch5 = new StandardChannelFeatureVO();
				ch5.setChannelCode("05");
				ch5.setDescription("History");
				ch5.setSubscriptionRate(10);
				cable.addChannel(ch5);

				StandardChannelFeatureVO ch6 = new StandardChannelFeatureVO();
				ch6.setChannelCode("06");
				ch6.setDescription("Sports");
				ch6.setSubscriptionRate(10);
				cable.addChannel(ch6);

				StandardChannelFeatureVO ch7 = new StandardChannelFeatureVO();
				ch7.setChannelCode("07");
				ch7.setDescription("Education");
				ch7.setSubscriptionRate(10);
				cable.addChannel(ch7);

				PremiumChannelFeatureVO ch8 = new PremiumChannelFeatureVO();
				ch8.setChannelCode("08");
				ch8.setDescription("Premium Documentary");
				ch8.setSubscriptionRate(10);
				cable.addChannel(ch8);

				PremiumChannelFeatureVO ch9 = new PremiumChannelFeatureVO();
				ch9.setChannelCode("09");
				ch9.setDescription("Premium  MTV");
				ch9.setSubscriptionRate(10);
				cable.addChannel(ch9);

				PremiumChannelFeatureVO ch10 = new PremiumChannelFeatureVO();
				ch10.setChannelCode("10");
				ch10.setDescription("Premium  Entertainment");
				ch10.setSubscriptionRate(10);
				cable.addChannel(ch10);

				PremiumChannelFeatureVO ch11 = new PremiumChannelFeatureVO();
				ch11.setChannelCode("11");
				ch11.setDescription("Premium Lifestyle");
				ch11.setSubscriptionRate(10);
				cable.addChannel(ch11);

				PremiumChannelFeatureVO ch12 = new PremiumChannelFeatureVO();
				ch12.setChannelCode("12");
				ch12.setDescription("Premium Sports");
				ch12.setSubscriptionRate(10);
				cable.addChannel(ch12);

				PremiumChannelFeatureVO ch13 = new PremiumChannelFeatureVO();
				ch13.setChannelCode("13");
				ch13.setDescription("Premium News");
				ch13.setSubscriptionRate(10);
				cable.addChannel(ch13);

				PremiumChannelFeatureVO ch14 = new PremiumChannelFeatureVO();
				ch14.setChannelCode("14");
				ch14.setDescription("Premium History");
				ch14.setSubscriptionRate(10);
				cable.addChannel(ch14);

				PremiumChannelFeatureVO ch15 = new PremiumChannelFeatureVO();
				ch15.setChannelCode("15");
				ch15.setDescription("Premium Education");
				ch15.setSubscriptionRate(10);
				cable.addChannel(ch15);

				serialisedPlans.add(cable.serialised());

				MobileVoiceVO mobile = new MobileVoiceVO();
				mobile.setDescription("One/# mobile phone line service.");
				mobile.setMonthlySuscription(24.90);

				LocalCallFeatureVO localmobile = new LocalCallFeatureVO();
				localmobile.setDescription("Make local calls.");
				localmobile.setPerSecRate(0.015);
				mobile.setLocalCallFeatureVO(localmobile);

				DataServiceFeatureVO datamobile = new DataServiceFeatureVO();
				datamobile.setDescription("Unlimited data usage. Only applies for local data traffic.");
				datamobile.setSubscriptionRate(10);
				mobile.addOptionalFeatures(datamobile);

				IDDCallFeatureVO iddmobile = new IDDCallFeatureVO();
				iddmobile.setDescription("Make international calls.");
				iddmobile.setPerSecRate(0.05);
				mobile.addOptionalFeatures(iddmobile);

				RoamingCallFeatureVO roammobile = new RoamingCallFeatureVO();
				roammobile.setDescription("Make and recieve calls while overseas");
				roammobile.setPerSecRate(0.15);
				mobile.addOptionalFeatures(roammobile);

				serialisedPlans.add(mobile.serialised());

				DigitalVoiceVO digital = new DigitalVoiceVO();
				digital.setDescription("One/# residential fixed home phone line service.");
				digital.setMonthlySuscription(15.90);

				LocalCallFeatureVO localdigital = new LocalCallFeatureVO();
				localdigital.setDescription("Make local calls.");
				localdigital.setPerSecRate(0.01);
				digital.setLocalCallFeatureVO(localdigital);

				IDDCallFeatureVO idddigital = new IDDCallFeatureVO();
				idddigital.setDescription("Make international calls.");
				idddigital.setPerSecRate(0.04);
				digital.addOptionalFeatures(idddigital);

				CallTransferFeatureVO calldigital = new CallTransferFeatureVO();
				calldigital.setDescription("Transfer calls between 2 parties or talk to both at the same time.");
				calldigital.setSubscriptionRate(5);
				digital.addOptionalFeatures(calldigital);

				serialisedPlans.add(digital.serialised());

				DbUtil.saveDb( "data//plans.txt", serialisedPlans);
			}
		} catch (BadDbCallException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
